package org.hdl.anima.transport.support;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collection;

import javax.naming.OperationNotSupportedException;

import org.hdl.anima.AppConf;
import org.hdl.anima.transport.Channel;
import org.hdl.anima.transport.ChannelHandler;
import org.hdl.anima.transport.Codec;
import org.hdl.anima.transport.Constants;
import org.hdl.anima.transport.Server;
import org.hdl.anima.transport.RemoteException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author qiuhd
 * @since  2014-7-24
 * @version V1.0.0
 */
public abstract class AbstractServer extends AbstractEndpoint implements Server {

	private final static Logger logger = LoggerFactory.getLogger(AbstractServer.class);
	private InetSocketAddress bindAdress ;
	private int maxClients; 
	private int idleTimeout ;
	
	public AbstractServer(AppConf conf, ChannelHandler handler) throws RemoteException{
		this(conf, handler,null);
	}
	
	public AbstractServer(AppConf conf, ChannelHandler handler,Codec codec) throws RemoteException{
		super(conf, handler,codec);
		
		this.maxClients = conf.getInt(Constants.MAX_CLIENTS, Constants.DEFAULT_MAX_CLIENTS) ;
		this.idleTimeout = conf.getInt(Constants.CHANNEL_IDLE_TIMEOUT, Constants.DEFAULT_CHANNEL_IDLE_TIMEOUT);
		
		String host = conf.get(Constants.BIND_HOST, Constants.DEFAULT_BIND_HOST);
		int port = conf.getInt(Constants.BIND_PORT, Constants.DEFAULT_BIND_PORT);
		
		this.bindAdress = new InetSocketAddress(host, port) ;
		
		try {
			doOpen();
			logger.debug("Server bind successful,Host :{}, Port:",host,port);
		}catch (Throwable t) {
			logger.error("Bind {} failure !",this.bindAdress.toString());
			throw new RemoteException(t);
		}
	}

	public abstract void doOpen() throws Throwable ;
	
	public abstract void doClose() throws Throwable ;

	@Override
	public void close() {
		try {
			super.close();
		} catch (Throwable e) {
			logger.warn(e.getMessage(), e);
		}
		try {
			doClose();
		} catch (Throwable e) {
			logger.warn(e.getMessage(), e);
		}
	}

	@Override
    public void close(int timeout) {
//        ExecutorUtil.gracefulShutdown(executor ,timeout);
        close();
    }

    @Override
	public InetSocketAddress getLocalAddress() {
		return null;
	}

	@Override
	public void send(Object message) throws RemoteException {
		throw new RemoteException(new OperationNotSupportedException("send method")) ;
	}

	public SocketAddress getBindAddress() {
		return this.bindAdress;
	}
	
	public int getMaxClients() {
		return this.maxClients;
	}

	public int getIdleTimeout() {
		return idleTimeout;
	}

	@Override
	public void connected(Channel ch) throws RemoteException {
		Collection<Channel> channels = getChannels();
		if (maxClients > 0 && channels.size() > maxClients) {
			logger.error("Close channel " + ch + ", cause: The server "+ ch.getLocalAddress()+ " connections greater than max config " + maxClients);
			ch.close();
			return;
		}
		super.connected(ch);
	}
}

